import json
import re

from django import http
from django.contrib.auth import login, logout, authenticate
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect

# Create your views here.
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.views import View
from django_redis import get_redis_connection

from areas.models import Address, Area
from goods.models import SKU
from users.models import User
from utils.mail_token import encode_signature_mail_url, decode_signature_mail_url
from utils.response_code import RET
from tasks.mail import send_mail_celery
from django.conf import settings


class RegisterView(View):
    def get(self, request):
        return render(request, 'register_vue.html', {'error_name_message': 'django的模板数据'})

    # 用户注册接口
    def post(self, request):
        # 1, 初始化数据
        data = request.POST
        user_name = data.get('user_name')
        pwd = data.get('pwd')
        cpwd = data.get('cpwd')
        phone = data.get('phone')
        msg_code = data.get('msg_code')
        allow = data.get('allow')

        # 1,1 判断数据是否都有
        if not all([user_name, pwd, cpwd, phone, msg_code, allow]):
            return http.HttpResponseForbidden('参数不全')

        # 1,2 校验用户名
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', user_name):
            return http.HttpResponseForbidden('用户名格式有误')

        # 1,3 校验密码
        if not re.match(r'^[0-9A-Za-z]{8,20}$', pwd):
            return http.HttpResponseForbidden('密码格式有误')

        # 1,4 两遍密码是否相同
        if pwd != cpwd:
            return http.HttpResponseForbidden('两遍密码不同')

        # 1,5 校验手机号
        if not re.match(r'^1[3-9]\d{9}$', phone):
            return http.HttpResponseForbidden('手机号格式不正确')

        # 1,6 校验短信验证码
        redis_conn = get_redis_connection('verify_code')
        redis_sms_code = redis_conn.get('sms_%s' % phone)
        if redis_sms_code:
            redis_sms_code = redis_sms_code.decode()
        if msg_code != redis_sms_code:
            return http.HttpResponseForbidden('短信验证码错误')

        if allow != 'on':
            return http.HttpResponseForbidden('请同意用户协议')

        # 2, 处理业务
        # 2,1 创建用户
        try:
            user = User.objects.create_user(username=user_name, password=pwd, mobile=phone)
        except Exception as e:
            # return render(request, 'register_vue.html', {'register_errmsg': '注册失败'})
            return http.HttpResponseForbidden('注册失败')

        # 把user指代的用户进行了登录操作
        login(request, user)
        # 3, 返回响应
        # url = reverse('')
        return redirect('/')

        pass


# 用户名重复检测
class UsernameCountView(View):
    def get(self, request, username):
        # 1, 初始化数据
        pass

        # 2, 处理业务逻辑
        count = User.objects.filter(username=username).count()

        # 3, 返回响应
        res = {
            'code': RET.OK,
            'errmsg': 'success',
            'count': count
        }

        return http.JsonResponse(res)


# 手机号重复检测
class MobileCountView(View):
    def get(self, request, mobile):
        # 1,初始化数据
        pass

        # 2,处理业务逻辑
        count = User.objects.filter(mobile=mobile).count()

        # 3,返回响应
        res = {
            'code': RET.OK,
            'errmsg': 'success',
            'count': count
        }
        return http.JsonResponse(res)


class LoginView(View):
    """用户名登录"""

    def get(self, request):
        """
        提供登录界面
        :param request: 请求对象
        :return: 登录界面
        """
        return render(request, 'login.html')
        pass

    def post(self, request):
        """
        实现登录逻辑
        :param request: 请求对象
        :return: 登录结果
        """
        # 1, 初始化数据, 获取数据, 校验数据
        username = request.POST.get('username')
        password = request.POST.get('pwd')
        remembered = request.POST.get('remembered')

        if not all([username, password]):
            return http.HttpResponseForbidden('参数不全')

        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('用户名格式错误')

        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden('密码格式错误')

        # 2, 处理业务逻辑
        # try:
        #     user = User.objects.get(username=username)
        #
        # except Exception as e:
        #     pass
        #     # return http.HttpResponseForbidden('用户不存在')
        # try:
        #     user = User.objects.get(mobile=username)
        # except Exception as e:
        #     return http.HttpResponseForbidden('用户不存在')
        #
        # # 密码没有检查通过
        # if not user.check_password(password):
        #     return http.HttpResponseForbidden('密码不正确')

        user = authenticate(username=username, password=password)

        if not user:
            return http.HttpResponseForbidden('用户名密码错误!')

        login(request, user)
        # 3, 返回响应
        response = redirect('/')
        response.set_cookie('username', user.username)

        return response
        pass


class LogoutView(View):
    def get(self, request):
        # 1, 初始化数据
        pass

        # 2, 处理业务逻辑
        logout(request)

        # 3, 返回响应
        response = redirect('/')
        response.delete_cookie('username')

        return response


class LoginRequiedView(View):
    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)


class UserCenterView(LoginRequiedView):
    # @method_decorator(login_required)
    def get(self, request):
        # 1, 判断用户是否是登录状态, 如果不是跳转到登录页面

        # 使用 user自带的  is_authenticated()  方法判断用户是否是登录状态
        # if request.user.is_authenticated():
        #     pass
        # else:
        #     return redirect('/login/')

        context = {
            'username': request.user.username,
            'mobile': request.user.mobile,
            'email': request.user.email,
            'email_active': request.user.email_active
        }

        return render(request, 'user_center_info.html', context=context)


class EmailView(LoginRequiedView):
    def put(self, request):
        # 1, 初始化数据
        data = json.loads(request.body.decode())
        email = data.get('email')

        # 1,2 校验
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '邮箱格式有误'})

        # 2, 处理业务逻辑
        user = request.user
        user.email = email
        user.save()

        token_str = encode_signature_mail_url({'user': user.username})
        verify_url = settings.EMAIL_VERIFY_URL + '?token=' + token_str
        # 'http://www.meiduo.site:8000/emails/verification/?token=awefasfasfw.aweraweafse.faweaewfaesfa

        send_mail_celery.delay('验证邮件', verify_url, user.email)

        # 3, 返回响应
        res = {
            'code': RET.OK,
            'errmsg': '完成'
        }
        return http.JsonResponse(res)


class EmailVerifyView(View):
    def get(self, request):
        # 1, 初始化数据
        # http: // www.meiduo.site: 8000 / emails / verification /?token = awefasfasfwfa
        token = request.GET.get('token')
        try:
            data = decode_signature_mail_url(token)
        except Exception as e:
            data = None
        # data = {'user': user.username}
        if not data:
            return http.HttpResponseForbidden('token失效!')

        username = data.get('user')
        try:
            user = User.objects.get(username=username)
        except Exception as e:
            user = None

        if not user:
            return http.HttpResponseForbidden('无效用户!')

        # 2, 处理业务
        user.email_active = True
        user.save()

        # 3, 返回响应
        return redirect('/user_center/')


class AddressView(LoginRequiedView):
    def get(self, request):
        # 1,初始化数据
        user = request.user

        # 2,处理业务逻辑
        # 取用户的地址列表
        addresses = user.addresses.filter(is_deleted=False)
        addresses_list = []
        for address in addresses:
            address_data = {
                'id': address.id,  # 前端需要id来判断是否和默认地址id相同
                'title': address.title,
                'receiver': address.receiver,
                'province': address.province.name,  # <Area: 山西省>
                'province_id': address.province.id,  # <Area: 山西省>
                'city': address.city.name,
                'city_id': address.city.id,
                'district': address.district.name,
                'district_id': address.district.id,
                'place': address.place,
                'mobile': address.mobile,
                'tel': address.tel,
                'email': address.email,
            }
            addresses_list.append(address_data)

        # 3,返回响应

        context = {
            'addresses': json.dumps(addresses_list),
            'default_address_id': user.default_address_id
        }
        return render(request, 'user_center_site.html', context=context)


class CreateAddressView(LoginRequiedView):
    def post(self, request):
        # 1,初始化数据
        data = json.loads(request.body.decode())
        """
        city_id: 440100
        district_id: 440106
        email: ""
        mobile: "13312341234"
        place: "珠吉路58号"
        province_id: 440000
        receiver: "张三"
        tel: ""
        title: "张三"
        """
        city_id = data.get('city_id')
        district_id = data.get('district_id')
        email = data.get('email')
        mobile = data.get('mobile')
        place = data.get('place')
        province_id = data.get('province_id')
        receiver = data.get('receiver')
        tel = data.get('tel')
        title = data.get('title')

        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden('参数email有误')

        # 2,处理业务逻辑
        try:
            address = Address.objects.create(
                user=request.user,
                title=title,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district=Area.objects.get(id=district_id),
                # district_id = district_id
                place=place,
                mobile=mobile,
                tel=tel,
                email=email,
            )
            # address.save()  # ?
        except Exception as e:
            return http.JsonResponse({'code': '', 'errmsg': '地址创建失败'})

        # 3,返回响应
        address_data = {
            'id': address.id,  # 前端需要id来判断是否和默认地址id相同
            'title': address.title,
            'receiver': address.receiver,
            'province': address.province.name,  # <Area: 山西省>
            'province_id': address.province.id,  # <Area: 山西省>
            'city': address.city.name,
            'city_id': address.city.id,
            'district': address.district.name,
            'district_id': address.district.id,
            'place': address.place,
            'mobile': address.mobile,
            'tel': address.tel,
            'email': address.email,
        }
        res = {
            'code': RET.OK,
            'errmsg': '地址创建成功',
            'address': address_data
        }
        return http.JsonResponse(res)


class UpdateDestroyAddressView(LoginRequiedView):
    def put(self, request, address_id):
        # 更新地址信息
        # 1,初始化数据
        data = json.loads(request.body.decode())
        receiver = data.get('receiver')
        province_id = data.get('province_id')
        city_id = data.get('city_id')
        district_id = data.get('district_id')
        place = data.get('place')
        mobile = data.get('mobile')
        tel = data.get('tel')
        email = data.get('email')
        # 校验数据
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden('参数email有误')

        # 2,处理业务逻辑
        try:
            Address.objects.filter(id=address_id).update(
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )
        except Exception as e:
            return http.JsonResponse({'code': RET.DBERR, 'errmsg': '数据更新失败'})

        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return http.JsonResponse({'code': RET.DBERR, 'errmsg': '数据读取失败'})

        # 3,返回响应
        address_data = {
            'id': address.id,  # 前端需要id来判断是否和默认地址id相同
            'title': address.title,
            'receiver': address.receiver,
            'province': address.province.name,  # <Area: 山西省>
            'province_id': address.province.id,  # <Area: 山西省>
            'city': address.city.name,
            'city_id': address.city.id,
            'district': address.district.name,
            'district_id': address.district.id,
            'place': address.place,
            'mobile': address.mobile,
            'tel': address.tel,
            'email': address.email,
        }

        res = {
            'code': RET.OK,
            'errmsg': '修改成功',
            'address': address_data
        }

        return http.JsonResponse(res)

        pass

    def delete(self, request, address_id):
        # 删除地址
        # 1, 初始化数据
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return http.JsonResponse({'code': RET.DBERR, 'errmsg': '地址编号有误'})

        # 2, 处理业务逻辑
        address.is_deleted = True
        address.save()

        # 3, 返回响应
        res = {
            'code': RET.OK,
            'errmsg': '删除成功'
        }
        return http.JsonResponse(res)
        pass


class DefaultAddressView(LoginRequiedView):
    def put(self, request, address_id):
        # 设置默认地址
        # 1,初始化数据
        user = request.user
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '地址编号错误'})

        # 2,处理业务逻辑
        # user.default_address = address
        user.default_address_id = address_id
        user.save()

        # 3,返回响应
        res = {
            'code': RET.OK,
            'errmsg': '默认地址更新成功'
        }
        return http.JsonResponse(res)
        pass


class UpdateTitleAddressView(LoginRequiedView):
    def put(self, request, address_id):
        # 1,初始化数据
        # 获取数据
        data = json.loads(request.body.decode())
        title = data.get('title')
        if not all([title]):
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '没有标题!'})
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '地址编号错误'})
        # 2,处理业务
        address.title = title
        address.save()

        # 3,返回响应
        res = {'code': RET.OK, 'errmsg': '修改标题成功'}
        return http.JsonResponse(res)
        pass


class PasswordChangeView(LoginRequiedView):
    def get(self, request):
        return render(request, 'user_center_pass.html')

    def post(self, request):
        # 修改密码
        # 1,初始化数据
        data = request.POST
        old_pwd = data.get('old_pwd')
        new_pwd = data.get('new_pwd')
        new_cpwd = data.get('new_cpwd')

        user = request.user

        if not user.check_password(old_pwd):
            return http.HttpResponseForbidden('密码不正确')

        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_pwd):
            return http.HttpResponseForbidden('密码格式不正确')

        if new_pwd != new_cpwd:
            return http.HttpResponseForbidden('两遍密码不一致')

        if old_pwd == new_pwd:
            return http.HttpResponseForbidden('新密码和旧密码不能相同')

        # 2,处理业务
        user.set_password(new_pwd)
        user.save()

        # 3,返回响应
        logout(request)
        response = redirect('/login/')
        response.delete_cookie('username')

        return response

        pass


class UserBrowseHistory(LoginRequiedView):
    def post(self, request):
        # 保存浏览记录
        # 1, 初始化数据
        user = request.user
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')

        try:
            sku = SKU.objects.get(id=sku_id)
        except Exception as e:
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '商品编号错误'})

        # 2, 处理业务逻辑
        # 2,1保存到redis中, 先获取一个redis的链接
        redis_conn = get_redis_connection('history')
        pipeline = redis_conn.pipeline()
        # 2,2 去重, key的名字: history_user_id
        # lrem history_1 0 16
        pipeline.lrem('history_%s' % user.id, 0, sku_id)
        # 2,3 增加
        pipeline.lpush('history_%s' % user.id, sku_id)
        # 2,4 截取
        pipeline.ltrim('history_%s' % user.id, 0, 4)
        pipeline.execute()

        # 3, 返回响应
        res = {
            'code': RET.OK,
            'errmsg': '成功'
        }
        return http.JsonResponse(res)

        pass

    def get(self, request):
        # 获取用户的浏览记录
        # 1, 初始化数据
        user = request.user

        # 2, 处理业务逻辑
        # 2,1 获取一个redis_conn
        redis_conn = get_redis_connection('history')
        # 2,2 从redis中取出用的浏览记录列表
        sku_id_list = redis_conn.lrange('history_%s' % user.id, 0, -1)
        # 2,3 根据sku_id 组织数据
        skus = []
        for sku_id in sku_id_list:
            sku = SKU.objects.get(id=sku_id)
            sku_data = {
                'id': sku.id,
                'default_image_url':sku.default_image_url.url,
                'name':sku.name,
                'price':sku.price
            }
            skus.append(sku_data)

        # 3, 返回响应
        res = {
            'code': RET.OK,
            'errmsg': '成功',
            'skus': skus
        }
        return http.JsonResponse(res)
        pass



"""
1, :
    接收: username, image_code, 验证
    业务: 
        返回该用户的mobile,token(mobile)
    结果:
        展示手机号页面, 可以发送短信   
        
2,1 :
    接收:token
    业务:
        解密token, 获取mobile
        给mobile发送短信验证码
    结果:
        用户收到短信, 填写在页面上, 点击下一步    
        
2,2 :
    接收:mobile, sms_code
    业务:
        判断一下这个mobile的sms_code是否和redis中的一致
        返回验证成功, 返回token(用户id) 
    结果:
        用户到第三步, 展示输入两次密码输入框,(隐含了token)

3,1 :
    接收:两次密码 , token(id)
    业务:
        判断两次密码是否一致
        给该用户重置密码
    结果, 返回成功, 前端跳转到首页
"""